// typeScript code

// 1、基本数据类型
let num: number = 123; // 数字类型
let str: string = "hello world"; // 字符串类型
let bool: boolean = true; // 布尔类型
let arr: number[] = [1, 2, 3]; // 数组类型
let arr1: Array<number> = [1, 2, 3]; // 泛型数组类型
let obj: object = { name: "Tom", age: 20 }; // 对象类型
// let sym: symbol = Symbol("key"); // 符号类型
let turple: [string, number] = ["hello", 123]; // 元组类型

// 2、任意值类型
let anyVal: any = "hello world"; // 任意值类型
console.log(anyVal.length); // 输出：11
let un: unknown = "";
// un.toString() // 编译报错，因为unknown类型不能调用toString方法

let n: null = null; // 空值类型
let u: undefined = undefined; // 未定义值类型

// 枚举类型，可以正向获取值，也可以反向获取键名
enum Color {
  Red,
  Green,
  Blue,
}
console.log(Color.Red); // 输出：0
console.log(Color[1]); // 输出："Green"

enum Color1 {
  Red = 1,
  Green,
  Blue,
}
console.log(Color1.Red); // 输出：1
console.log(Color1[1]); // 输出："Red"

// 3、函数类型
function add(x: number, y: number): number {
  return x + y;
}
// void
function log(message: string): void {
  console.log(message);
}
// never
function error(): never {
  throw new Error("error");
}

// 4、接口类型
interface Person {
  name: string;
  age: number;
  [prop: string]: string | number;
}
let tom: Person = {
  name: "Tom",
  age: 20,
  gender: "male",
};

interface Prices {
  [index: number]: number;
}

let prices: Prices = [10, 20, 30];

// 额外属性检查
interface IArea {
  width: number;
  height: number;
}

// 方法一：使用类型断言
let area: IArea = {
  width: 10,
  height: 20,
  length: 30, // 编译报错，因为IArea接口中没有定义length属性
} as IArea;

// 方法二：使用接口拓展
let area1 = {
  width: 10,
  height: 20,
  length: 30, // 编译报错，因为IArea接口中没有定义length属性
};

let area2: IArea = area1;

console.log("------function------");

function calc(x: number, y: number): number {
  return x + y;
}
let result = calc(10, 20);

interface ICalc {
  (x: number, y: number): number;
}
let calc1: ICalc = function (x: number, y: number): number {
  return x + y;
};

function calc2(
  callback: (x: number, y: number) => number, // ICalc
  x: number,
  y: number
): void {
  callback(x, y);
}
console.log(calc2(calc1, 10, 20));

console.log("------class------");

interface IShape {
  width: number;
  height: number;
  area: number;
  calc(): number;
}

class triangle implements IShape {
  width: number;
  height: number;
  area: number;
  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
    this.area = (width * height) / 2;
  }
  calc(): number {
    return this.area;
  }
}

let t = new triangle(11, 22);
console.log(t.calc());

interface IShapeConstructor {
  new (width: number, height: number): IShape;
}

class shapeFactory {
  static createShape(shapeConstructor: IShapeConstructor, width: number, height: number): IShape {
    return new shapeConstructor(width, height);
  }
}
let s = shapeFactory.createShape(triangle, 11, 22);
console.log(s.calc());
